﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Twodi.Input.Events;

namespace Twodi.Input
{
    /// <summary>
    /// Botões do mouse.
    /// </summary>
    public enum MouseButton
    {
        Left = 0,
        Right,
        Middle,
        LeftAux,
        RightAux,
        Any
    }

    /// <summary>
    /// Objeto que contem informações de input do mouse, utilizando dois estados como meio de controle.
    /// </summary>
    public class MouseInput : AbstractInput<MouseState, MouseEvent>
    {
        private Vector2 position = new Vector2(-1, -1);

        /// <summary>
        /// Construtor do Controlador do Mouse.
        /// </summary>
        /// <param name="game">Game associado ao Controlador.</param>
        public MouseInput(Game game)
            : base(game)
        {
            State = Mouse.GetState();
        }

        /// <summary>
        /// Atualizar estados do mouse.
        /// </summary>
        /// <param name="gameTime">Tempo do jogo atual.</param>
        public override void Update(GameTime gameTime)
        {
            SwapStates();
            UpdatePosition();
            CallEvents();
            base.Update(gameTime);
        }

        /// <summary>
        /// Trocar mouse states antigo e novo.
        /// </summary>
        protected override void SwapStates()
        {
            base.SwapStates();
            State = Mouse.GetState();
        }

        /// <summary>
        /// Atualizar posição do mouse.
        /// </summary>
        private void UpdatePosition()
        {
            position = new Vector2(State.X, State.Y);
        }

        /// <summary>
        /// Transformar posição do mouse.
        /// </summary>
        /// <param name="transformation"></param>
        /// <param name="inverted"></param>
        /// <returns></returns>
        public Vector2 Transform(Matrix transformation)
        {
            Vector2.Transform(ref this.position, ref transformation, out position);
            return position;
        }

        /// <summary>
        /// Invocar eventos.
        /// </summary>
        protected override void CallEvents()
        {
            //Para cada evento dentro da lista de eventos.
            foreach (MouseEvent evente in Events)
            {
                //Se evento informa que deve parar o loop, pare.
                if (IsAnyButtonPressed && !evente.Handle(this))
                    break;
            }
        }

        /// <summary>
        /// Posição do mouse especificada em um Vector2.
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
        }

        /// <summary>
        /// Posição do Mouse especificada em um Point.
        /// </summary>
        public Point Point
        {
            get { return new Point((int)position.X, (int)position.Y); }
        }

        /// <summary>
        /// Posição X atual do Mouse.
        /// </summary>
        public int X
        {
            get { return State.X; }
        }

        /// <summary>
        /// Posição Y atual do Mouse.
        /// </summary>
        public int Y
        {
            get { return State.Y; }
        }

        /// <summary>
        /// Se mouse se moveu desde o ultimo estado.
        /// </summary>
        public bool Moved
        {
            get
            {
                return new Point(OldState.X, OldState.Y) != new Point(State.X, State.Y);
            }
        }

        /// <summary>
        /// Qualquer botão pressionado.
        /// </summary>
        public bool IsAnyButtonPressed
        {
            get
            {
                return IsButtonPressed(MouseButton.Any);
            }
        }

        /// <summary>
        /// Qualquer botão pressionado.
        /// </summary>
        public bool IsAnyButtonClicked
        {
            get
            {
                return IsButtonClick(MouseButton.Any);
            }
        }

        /// <summary>
        /// Botão esquerdo pressionado.
        /// </summary>
        public bool LeftPressed
        {
            get
            {
                return IsButtonPressed(MouseButton.Left);
            }
        }

        /// <summary>
        ///  Botão direito pressionado.
        /// </summary>
        public bool RightPressed
        {
            get
            {
                return IsButtonPressed(MouseButton.Right);
            }
        }

        /// <summary>
        ///  Botão central pressionado.
        /// </summary>
        public bool MiddlePressed
        {
            get
            {
                return IsButtonPressed(MouseButton.Middle);
            }
        }

        /// <summary>
        ///  Botão central pressionado.
        /// </summary>
        public bool LeftAuxPressed
        {
            get
            {
                return IsButtonPressed(MouseButton.LeftAux);
            }
        }

        /// <summary>
        ///  Botão central pressionado.
        /// </summary>
        public bool RightAuxPressed
        {
            get
            {
                return IsButtonPressed(MouseButton.RightAux);
            }
        }

        /// <summary>
        ///  Botão esquerdo clicado.
        /// </summary>
        public bool LeftClick
        {
            get
            {
                return IsButtonClick(MouseButton.Left);
            }
        }

        /// <summary>
        ///  Botão direito clicado.
        /// </summary>
        public bool RightClick
        {
            get
            {
                return IsButtonClick(MouseButton.Right);
            }
        }

        /// <summary>
        ///  Botão central clicado.
        /// </summary>
        public bool MiddleClick
        {
            get
            {
                return IsButtonClick(MouseButton.Middle);
            }
        }

        /// <summary>
        ///  Botão central clicado.
        /// </summary>
        public bool LeftAuxClick
        {
            get
            {
                return IsButtonClick(MouseButton.LeftAux);
            }
        }

        /// <summary>
        ///  Botão central clicado.
        /// </summary>
        public bool RightAuxClick
        {
            get
            {
                return IsButtonClick(MouseButton.RightAux);
            }
        }

        public bool IsButtonClick(MouseButton button)
        {
            switch (button)
            {
                case MouseButton.Left:
                    return OldState.LeftButton == ButtonState.Pressed && State.LeftButton == ButtonState.Released;
                case MouseButton.Right:
                    return OldState.RightButton == ButtonState.Pressed && State.RightButton == ButtonState.Released;
                case MouseButton.Middle:
                    return OldState.MiddleButton == ButtonState.Pressed && State.MiddleButton == ButtonState.Released;
                case MouseButton.LeftAux:
                    return OldState.XButton1 == ButtonState.Pressed && State.XButton1 == ButtonState.Released;
                case MouseButton.RightAux:
                    return OldState.XButton2 == ButtonState.Pressed && State.XButton2 == ButtonState.Released;
                case MouseButton.Any:
                    return LeftClick || RightClick || MiddleClick || LeftAuxClick || RightAuxClick;
            }

            return false;
        }

        public bool IsButtonPressed(MouseButton button)
        {
            switch (button)
            {
                case MouseButton.Left:
                    return OldState.LeftButton == ButtonState.Pressed;
                case MouseButton.Right:
                    return OldState.RightButton == ButtonState.Pressed;
                case MouseButton.Middle:
                    return OldState.MiddleButton == ButtonState.Pressed;
                case MouseButton.LeftAux:
                    return OldState.XButton1 == ButtonState.Pressed;
                case MouseButton.RightAux:
                    return OldState.XButton2 == ButtonState.Pressed;
                case MouseButton.Any:
                    return LeftPressed || RightPressed || MiddlePressed || LeftAuxPressed || RightAuxPressed;
            }

            return false;
        }

        /// <summary>
        /// Define se mouse default do windows deve ficar visivel.
        /// </summary>
        public bool Visible
        {
            get
            {
                return Game.IsMouseVisible;
            }
            set
            {
                Game.IsMouseVisible = value;
            }
        }
    }
}
